package com.dd.cloud.common.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dd.cloud.common.annotate.EncryptField;
import com.dd.cloud.common.constants.ZekeConstants;
import com.google.common.base.Joiner;
import lombok.SneakyThrows;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author zk
 */

public class ObjectUtils {


    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        return obj.toString();
    }

    public static boolean equalsAndNotNull(Object obj, Object oldObj) {
        if (obj == null || oldObj == null) {
            return false;
        }
        if (obj != oldObj) {
            return false;
        }
        return true;
    }

    /**
     * 将对象的属性按照拼音首字母排序, 并拼接成字符串, 参数加密用
     *
     * @param obj
     * @return
     */
    public static String pinyinSort(Object obj) {
        Class cls = obj.getClass();
        Map<String, String> map = new LinkedHashMap<String, String>();
        while (cls != null && cls != Object.class) {
            Field[] fields = cls.getDeclaredFields();
            for (Field fd : fields) {
                if (!fd.isAccessible()) {
                    fd.setAccessible(true);
                }
                try {
                    if (fd.get(obj) != null) {
                        String value = String.valueOf(fd.get(obj));
                        map.put(fd.getName(), value);
                    }
                    boolean hasSecureField = fd.isAnnotationPresent(EncryptField.class);
                    if (hasSecureField) {
                        fd.setAccessible(true);
                        String encryptValue = (String) fd.get(obj);
                        String value = AESUtil.decrypt(encryptValue, AESUtil.SECRET_KEY);
                        map.put(fd.getName(), value);
                    }

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            cls = cls.getSuperclass();
        }
        if (map.containsKey("sign")) {
            map.remove("sign");
        }
        map.put("secret", ZekeConstants.CommonConstants.SECRET);
        List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(map.entrySet());
        //排序
        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
            @SneakyThrows
            @Override
            public int compare(Map.Entry<String, String> s1, Map.Entry<String, String> s2) {
                String str1 = new String(s1.getKey().getBytes("GB2312"), "ISO-8859-1");
                String str2 = new String(s2.getKey().getBytes("GB2312"), "ISO-8859-1");
                return str1.compareTo(str2);
            }
        });
        String result = Joiner.on("&").join(infoIds);
        System.out.println("签名串" + result);
        return result;
    }


    public static Long toLong(Object obj) {
        if (obj == null) {
            return 0L;
        }
        if (obj instanceof Double || obj instanceof Float) {
            return Long.valueOf(StringUtils.substringBefore(obj.toString(), "."));
        }
        if (obj instanceof Number) {
            return Long.valueOf(obj.toString());
        }
        if (obj instanceof String) {
            return Long.valueOf(obj.toString());
        } else {
            return 0L;
        }
    }

    public static Integer toInt(Object obj) {
        return toLong(obj).intValue();
    }

    /**
     * parentId为当前List最上层父id
     * idKey为实体类对象中id键名
     * parentKey为实体类对象中id的键名
     * childName为返回数据子列表的命名
     */
    public static JSONArray forObjectToTreeMap(List<?> treeList, Long parentId, String idKey, String parentIdKey, String childName) {
        JSONArray childMenu = new JSONArray();
        for (Object object : treeList) {
            String jsonStr = JSONObject.toJSONString(object);
            JSONObject jsonMenu = JSONObject.parseObject(jsonStr);
            //JSONObject jsonMenu = JSONObject.parseObject(object);
            Long menuId = jsonMenu.getLong(idKey);
            Long pid = jsonMenu.getLong(parentIdKey);
            if (parentId.equals(pid)) {
                JSONArray array = forObjectToTreeMap(treeList, menuId, idKey, parentIdKey, childName);
                jsonMenu.put(childName, array);
                childMenu.add(jsonMenu);
            }
        }
        return childMenu;
    }

//    public static<T>  boolean checkDataIsIn  (Class cls, T obj){
//        List myAL =  refrect(cls, obj.getClass());
//        return myAL.contains(obj);
//    }

    /**
     * 反射获取对象所有属性值
     *
     * @param cls 需要获取数据的对象class
     * @param <T> 识别的类型
     * @return
     */
    public static <T> boolean refrect(Class cls, T cs) {
        Field[] fields = cls.getDeclaredFields();
        boolean flag = false;
        for (int i = 0; i < fields.length; i++) {
            try {
                Field f = fields[i];
                if (f.get(cls).equals(cs)) {
                    flag = true;
                    return flag;
                }
            } catch (IllegalAccessException e) {

            }
        }
        return flag;
    }


    /**
     * 判断对象是否为空，且对象的所有属性都为空
     * ps: boolean类型会有默认值false 判断结果不会为null 会影响判断结果
     * 序列化的默认值也会影响判断结果
     *
     * @param object
     * @return
     */
    public static boolean objCheckIsNull(Object object) {
        Class clazz = (Class) object.getClass(); // 得到类对象
        Field fields[] = clazz.getDeclaredFields(); // 得到所有属性
        boolean flag = true; //定义返回结果，默认为true
        for (Field field : fields) {
            field.setAccessible(true);
            Object fieldValue = null;
            if (field.getName().equals("serialVersionUID")) {
                continue;
            }
            try {
                fieldValue = field.get(object); //得到属性值
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            if (fieldValue != null) {  //只要有一个属性值不为null 就返回false 表示对象不为null
                flag = false;
                break;
            }
        }
        return flag;
    }


    /**
     * 将 Map对象转化为JavaBean
     *
     * @param map
     * @param T
     * @return
     * @throws Exception
     */
    public static <T> T convertMap2Bean(Map<String, Object> map, Class<T> T)
            throws Exception {
        if (map == null || map.size() == 0) {
            return null;
        }
        //获取map中所有的key值，全部更新成大写，添加到keys集合中,与mybatis中驼峰命名匹配
        Object mvalue = null;
        Map<String, Object> newMap = new HashMap<>();
        Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            String key = it.next().getKey();
            mvalue = map.get(key);
          /*  if (key.indexOf(CharacterConstant.UNDERLINE) != -1)
            {
                key = key.replaceAll(CharacterConstant.UNDERLINE, "");
            }*/
            newMap.put(key.toUpperCase(Locale.US), mvalue);
        }

        BeanInfo beanInfo = Introspector.getBeanInfo(T);
        T bean = T.newInstance();
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0, n = propertyDescriptors.length; i < n; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            String upperPropertyName = propertyName.toUpperCase();

            if (newMap.keySet().contains(upperPropertyName)) {
                Object value = newMap.get(upperPropertyName);
                //这个方法不会报参数类型不匹配的错误。
                BeanUtils.copyProperty(bean, propertyName, value);
            }
        }
        return bean;
    }

    /**
     * 将一个 JavaBean 对象转化为一个 Map
     *
     * @param bean
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static Map<String, Object> convertBean2Map(Object bean)
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        Class<? extends Object> type = bean.getClass();
        Map<String, Object> returnMap = new HashMap<>();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!"class".equals(propertyName)) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put(propertyName, result);
                } else {
                    returnMap.put(propertyName, null);
                }
            }
        }
        return returnMap;
    }

    /**
     * 将 List<Map>对象转化为List<JavaBean>
     *
     * @param listMap
     * @param T
     * @return
     * @throws Exception
     */
    public static <T> List<T> convertListMap2ListBean(List<Map<String, Object>> listMap, Class<T> T)
            throws Exception {
        List<T> beanList = new ArrayList<>();
        if (listMap != null && !listMap.isEmpty()) {
            for (int i = 0, n = listMap.size(); i < n; i++) {
                Map<String, Object> map = listMap.get(i);
                T bean = convertMap2Bean(map, T);
                beanList.add(bean);
            }
            return beanList;
        }
        return beanList;
    }

    /**
     * 将 List<JavaBean>对象转化为List<Map>
     *
     * @param beanList
     * @return
     * @throws Exception
     */
    public static <T> List<Map<String, Object>> convertListBean2ListMap(List<T> beanList, Class<T> T)
            throws Exception {
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (int i = 0, n = beanList.size(); i < n; i++) {
            Object bean = beanList.get(i);
            Map<String, Object> map = convertBean2Map(bean);
            mapList.add(map);
        }
        return mapList;
    }

    /**
     * 设置对象 基础类型默认值
     * 现支持 Integer/Double/Long/BigDecimal
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> T setBeanFiledDefaultValue(T t) {
        Class<?> cls = t.getClass();
        for (Field item : cls.getDeclaredFields()) {
            try {
                item.setAccessible(true);
                Object obj = item.get(t);
                if (obj == null) {
                    if (item.getType() == Integer.class) {
                        item.set(t, 0);
                    } else if (item.getType() == Double.class) {
                        item.set(t, 0.0);
                    } else if (item.getType() == Long.class) {
                        item.set(t, 0L);
                    } else if (item.getType() == BigDecimal.class) {
                        item.set(t, BigDecimal.valueOf(0));
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return t;
    }

    /**
     * 返回实体的所有非 null 字段 用于BeanUtils.copyProperties替换非空的字段
     *
     * @param source
     * @return
     */
    public static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static byte[] base64EncodeUrl(byte[] input) {
        byte[] base64 = Base64.getEncoder().encode(input);
        for (int i = 0; i < base64.length; ++i) {
            switch (base64[i]) {
                case '+':
                    base64[i] = '*';
                    break;
                case '/':
                    base64[i] = '-';
                    break;
                case '=':
                    base64[i] = '_';
                    break;
                default:
                    break;
            }
        }
        return base64;
    }
}